//
//  Method.swift
//  cnswift-demo
//
//  Created by YangWei on 2020/12/30.
//  Copyright © 2020 YangWei. All rights reserved.
//

import UIKit

/// 1 实例方法（Instance Methods）
/// 1.1 self 属性
/// 一个很简单的 Counter 类，Counter 能被用来对一个动作发生的次数进行计数
class Counter {
    // 一个可变属性 count，用它来保持对当前计数器值的追踪
    var count = 0
    // 让计数器按一递增
    func increment() {
        count += 1
        // 1.1 self 属性: increment 方法还可以这样写
//        self.count += 1
    }
    // 让计数器按一个指定的整数值递增
    func increment(by amount: Int) {
        count += amount
    }
    // 将计数器重置为0
    func reset() {
        count = 0
    }
}

/// 1.1 self 属性
/// 1.2 在实例方法中修改值类型
/// 1.3 在可变方法中给 self 赋值
struct PointV2 {
    var x = 0.0, y = 0.0
    func isToTheRightOf(x: Double) -> Bool {
        // 形参名和属性名相同，使用 self 避免歧义
        return self.x > x
    }
    
    // 使用 可变方法，将关键字 mutating 放到方法的 func 关键字之前
    mutating func moveBy(x deltaX: Double, y deltaY: Double) {
        x += deltaX
        y += deltaY
    }
    
    // 可变方法能够给隐含属性 self 赋一个全新的实例
    mutating func moveByV2(x deltaX: Double, y deltaY: Double) {
        // 创建了一个新的结构体实例
        self = PointV2(x: x + deltaX, y: y + deltaY)
    }
}

/// 1.3 在可变方法中给 self 赋值
/// 设置隐含的 self 属性为相同枚举里的不同成员
/// 定义一个三态切换的枚举：每次调用 next() 方法时，开关在不同的电源状态（off, low, high）之间循环切换。
enum TriStateSwitch {
    case off, low, high
    mutating func next() {
        switch self {
        case .off:
            self = .low
        case .low:
            self = .high
        case .high:
            self = .off
        }
    }
}

/// 2 类型方法
class SomeClassV3 {
    class func someTypeMethod() {
        // 在这里实现类型方法
    }
}

/// 2 类型方法
/// 监测玩家的游戏发展情况（游戏的不同层次或阶段）
/// 一个单人游戏，可以存储多个玩家在同一设备上的游戏信息
/// 游戏初始时，所有的游戏等级（除了等级 1）都被锁定。
/// 每次有玩家完成一个等级，这个等级就对这个设备上的所有玩家解锁。
/// LevelTracker 结构体用类型属性和方法监测游戏的哪个等级已经被解锁。
/// 还监测每个玩家的当前等级
struct LevelTracker {
    // 玩家已解锁的最高等级。存储在类型属性 highestUnlockedLevel 中
    static var highestUnlockedLevel = 1
    
    // 用实例属性 currentLevel 来监测每个玩家当前的等级
    var currentLevel = 1
    
    // 类型方法 一旦新等级被解锁，更新 highestUnlockedLevel 的值
    static func unlock(_ level: Int) {
        if level > highestUnlockedLevel { highestUnlockedLevel = level }
    }
    
    // 类型方法，如果某个给定的等级已经被解锁，它将返回 true。
    static func isUnlocked(_ level: Int) -> Bool {
        // 不使用 LevelTracker.highestUnlockedLevel 写法，也能够访问类型属性 highestUnlockedLevel
        return level <= highestUnlockedLevel
    }
    
    // 允许在调用 advance(to:) 时候忽略返回值，不会产生编译警告
    @discardableResult
    // 实例方法 在更新 currentLevel 之前检查所请求的新等级是否已经解锁。
    // 返回布尔值以指示是否能够设置 currentLevel
    mutating func advance(to level: Int) -> Bool {
        if LevelTracker.isUnlocked(level) {
            currentLevel = level
            return true
        } else {
            return false
        }
    }
}

/// 2 类型方法
/// 与 LevelTracker 结构体共同使用来追踪和更新每一个玩家的进度：
class Player {
    // 创建一个新的 LevelTracker 实例来监测这个用户的进度
    var tracker = LevelTracker()
    let playerName: String
    
    // 一旦玩家完成某个指定等级就调用它
    // 为所有玩家解锁下一等级，并且将当前玩家的进度更新为下一等级
    func complete(level: Int) {
        LevelTracker.unlock(level + 1)
        tracker.advance(to: level + 1)
    }
    init(name: String) {
        playerName = name
    }
}

class Methods: SWDBaseObject {
    
    class func run() {
        
        let methods = Methods()
        
        // 1
        methods.instanceMethods()
        
        // 1.1
        methods.theSelfProperty()
        
        // 1.2
        methods.modifyingValueTypesFromWithinInstanceMethods()
        
        // 1.3
        methods.assigningToSelfWithinAMutatingMethod()
        
        // 2
        methods.typeMethods()
    }
    
    /// 1 实例方法（Instance Methods）
    func instanceMethods() {
        let title = "1 实例方法（Instance Methods）";
        printStartLine(title)
        
        // 看 Counter 的实例方法定义
        let counter = Counter()
        // 初始计数值是0
        print(counter.count)
        
        counter.increment()
        // 计数值现在是1
        print(counter.count)
        
        counter.increment(by: 5)
        // 计数值现在是6
        print(counter.count)
        
        counter.reset()
        // 计数值现在是0
        print(counter.count)
        
        printEndLine(title)
    }
    
    /// 1.1 self 属性
    func theSelfProperty() {
        let title = "1.1 self 属性";
        printStartLine(title)

        let somePoint = PointV2(x: 4.0, y: 5.0)
        if somePoint.isToTheRightOf(x: 1.0) {
            print("This point is to the right of the line where x == 1.0")
        }
        // 打印“This point is to the right of the line where x == 1.0”
        
        printEndLine(title)
    }
    
    /// 1.2 在实例方法中修改值类型
    func modifyingValueTypesFromWithinInstanceMethods() {
        let title = "1.2 在实例方法中修改值类型";
        printStartLine(title)

        var somePoint = PointV2(x: 1.0, y: 1.0)
        somePoint.moveBy(x: 2.0, y: 3.0)
        print("The point is now at (\(somePoint.x), \(somePoint.y))")
        // 打印“The point is now at (3.0, 4.0)”
        
        /*
         不能在结构体类型的常量（a constant of structure type）上调用可变方法
         因为其属性不能被改变，即使属性是变量属性
         */
        /*
         let fixedPoint = Point(x: 3.0, y: 3.0)
         fixedPoint.moveBy(x: 2.0, y: 3.0)
         // 这里将会报告一个错误 ❌
         */
        
        printEndLine(title)
    }
    
    /// 1.3 在可变方法中给 self 赋值
    func assigningToSelfWithinAMutatingMethod() {
        let title = "1.3 在可变方法中给 self 赋值";
        printStartLine(title)

        var somePoint = PointV2(x: 1.0, y: 1.0)
        somePoint.moveByV2(x: 2.0, y: 3.0)
        print("The point is now at (\(somePoint.x), \(somePoint.y))")
        // 打印“The point is now at (3.0, 4.0)”
        
        var ovenLight = TriStateSwitch.low
        print(ovenLight)
        
        ovenLight.next()
        // ovenLight 现在等于 .high
        print(ovenLight)
        
        ovenLight.next()
        // ovenLight 现在等于 .off
        print(ovenLight)
        
        printEndLine(title)
    }
    
    /// 2 类型方法
    func typeMethods() {
        let title = "2 类型方法";
        printStartLine(title)
        
        // 类型方法调用语法示例
        SomeClassV3.someTypeMethod()
        
        // 一个新的玩家创建一个 Player 的实例，然后看这个玩家完成等级一时发生了什么：
        var player = Player(name: "Argyrios")
        player.complete(level: 1)
        print("highest unlocked level is now \(LevelTracker.highestUnlockedLevel)")
        // 打印“highest unlocked level is now 2”

        // 创建了第二个玩家，并尝试让他开始一个没有被任何玩家解锁的等级，那么试图设置玩家当前等级将会失败
        player = Player(name: "Beto")
        if player.tracker.advance(to: 6) {
            print("player is now on level 6")
        } else {
            print("level 6 has not yet been unlocked")
        }
        // 打印“level 6 has not yet been unlocked”
        
        printEndLine(title)
    }
    
}
